﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Tao.FreeGlut;
using Tao.OpenGl;
using System.Diagnostics;
using System.Threading;
using Phys;
using Phys.Model;
using Phys.Loader;
using System.Windows.Threading;
using TWiStEr.OpenGL.Utilities;

namespace Phys.UI {
	public partial class PhysicsGLWindow {
		public PhysicsGLWindow() {
			Glut.glutInit();
			InitWindow();
			InitCallbacks();
			InitMenu();
			InitDrawers();
			Debug.WriteLine(string.Format("current window is {0}x{1}@{2},{3}",
					Glut.glutGet(Glut.GLUT_WINDOW_WIDTH), Glut.glutGet(Glut.GLUT_WINDOW_HEIGHT),
					Glut.glutGet(Glut.GLUT_WINDOW_X), Glut.glutGet(Glut.GLUT_WINDOW_Y)
			), "Camera");
		}

		private static void InitWindow() {
			Glut.glutInitDisplayMode(Glut.GLUT_RGBA | Glut.GLUT_DOUBLE | Glut.GLUT_DEPTH);
			Glut.glutInitWindowPosition(100, 100);
			Glut.glutInitWindowSize(640, 480);
			Glut.glutCreateWindow("Physics simulation");
		}

		private void InitCallbacks() {
			Glut.glutDisplayFunc(GL_Display);
			Glut.glutReshapeFunc(GL_Reshape);
			//Glut.glutSpecialFunc(GL_Special);
			Glut.glutKeyboardFunc(GL_Keyboard);
			Glut.glutMotionFunc(GL_MouseMove);
			Glut.glutPassiveMotionFunc(GL_PassiveMouseMove);
			Glut.glutIdleFunc(GL_Idle);
		}
		private void InitMenu() {
			//int subMenuA = Glut.glutCreateMenu(GL_Menu);
			//Glut.glutAddMenuEntry("Sub menu A1 (01)", 1);
			//Glut.glutAddMenuEntry("Sub menu A2 (02)", 2);
			//Glut.glutAddMenuEntry("Sub menu A3 (03)", 3);

			//int subMenuB = Glut.glutCreateMenu(GL_Menu);
			//Glut.glutAddMenuEntry("Sub menu B1 (04)", 4);
			//Glut.glutAddMenuEntry("Sub menu B2 (05)", 5);
			//Glut.glutAddMenuEntry("Sub menu B3 (06)", 6);
			//Glut.glutAddSubMenu("Going to sub menu A", subMenuA);

			//int menuID = Glut.glutCreateMenu(GL_Menu);
			//Glut.glutAddMenuEntry("Entry one", 1);
			//Glut.glutAddMenuEntry("Entry two", 2);
			//Glut.glutAddMenuEntry("Entry three", 3);
			//Glut.glutAddMenuEntry("Entry four", 4);
			//Glut.glutAddMenuEntry("Entry five", 5);
			//Glut.glutAddSubMenu("Enter sub menu A", subMenuA);
			//Glut.glutAddSubMenu("Enter sub menu B", subMenuB);
			//Glut.glutAttachMenu(Glut.GLUT_RIGHT_BUTTON);
		}

		public WorldObject World { get; private set; }
		private void InitPhysics(WorldObject world) {
			World = world;
			World.Started += (o, e) => Debug.WriteLine("World Started", "Physics");
			World.Updated += (o, e) => doPostRedisplay = true;
			World.Stopped += (o, e) => Debug.WriteLine("World Stopped", "Physics");
		}
		/// <summary>
		/// Refernce to the Thread running Glut not to let the Garbage Collector take it away.
		/// </summary>
		private Thread __gc_GlutThread;
		public void Start(string filename) {
			var world = WorldLoader.LoadXml(filename);
			InitPhysics(world);
			if (__gc_GlutThread != null) throw new InvalidOperationException("Glut already started");
			__gc_GlutThread = new Thread(
				() => Glut.glutMainLoop()
			);
			__gc_GlutThread.Name = "Glut Main Loop Background Thread";
			__gc_GlutThread.IsBackground = true;
			LoadSettings(filename);
			__gc_GlutThread.Start();
		}
		/// <summary>
		/// Closes the GL Window.
		/// TODO: figure out why exits app
		/// </summary>
		public void Close() {
			Glut.glutDestroyWindow(Glut.glutGetWindow());
			//System.Windows.Application curr = App.Current;
			//curr.Dispatcher.Invoke(new Action(() => curr.Shutdown()));
		}

		/// <summary>
		/// Camera to let movement with mouse and keyboard as in an FPS game.
		/// </summary>
		private Camera cam = new Camera(1, 1, 8);
		private void GL_Reshape(int nWidth, int nHeight) {
			Debug.WriteLine(string.Format("{0}x{1}", nWidth, nHeight), "Camera");
			Gl.glViewport(0, 0, nWidth, nHeight);
			cam.SetWindowSize(nWidth, nHeight);
			cam.glSetMatrices();

			//Gl.glEnable(Gl.GL_CULL_FACE);
			Gl.glShadeModel(Gl.GL_SMOOTH);
			Gl.glPolygonMode(Gl.GL_FRONT, Gl.GL_FILL);
			Gl.glPolygonMode(Gl.GL_BACK, Gl.GL_LINE);
			Gl.glEnable(Gl.GL_DEPTH_TEST);
			Gl.glEnable(Gl.GL_NORMALIZE);

			Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_POSITION, new[] { 10f, 10f, 10f });
			Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_AMBIENT, new[] { .3f, .3f, .3f, 1f });
			Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_DIFFUSE, new[] { .4f, .4f, .4f, 1f });
			Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_SPECULAR, new[] { .9f, .9f, .9f, 1f });
			Gl.glEnable(Gl.GL_LIGHT0);
			Gl.glEnable(Gl.GL_LIGHTING);
			Gl.glEnable(Gl.GL_COLOR_MATERIAL);
			Gl.glEnable(Gl.GL_BLEND);
			Gl.glBlendFunc(Gl.GL_SRC_ALPHA, Gl.GL_ONE_MINUS_SRC_ALPHA);
			Gl.glColorMaterial(Gl.GL_FRONT_AND_BACK, Gl.GL_AMBIENT_AND_DIFFUSE);
		}
	}
}
